#include <iostream>
#include <vector>
#include <functional>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <cstring>
using namespace std;

// // 阻塞式IO
// int main()
// {
//     char buffer[64];
//     while (true)
//     {
//         printf(">>>");
//         fflush(stdout);
//         int n = read(0, buffer, sizeof(buffer)); // read字节流读取
//         buffer[n - 1] = 0;                       // 干掉'\n'
//         cout << "echo#" << buffer << endl;
//     }
//     return 0;
// }

void PrintLog()
{
    cout<<"这是一个打印日志的例程"<<endl;
}
void OperMysql()
{
    cout<<"这是一个操作数据库的例程"<<endl;
}
void CheckNet()
{
    cout<<"这是一个检查网络的例程"<<endl;
}
using func_t = function<void (void)>;
vector<func_t> funcs;

void LoadAllTask()
{
    funcs.push_back(PrintLog);
    funcs.push_back(OperMysql);
    funcs.push_back(CheckNet);
}
void PrintAllTask()
{
    for(auto& func : funcs) func();
}


//基于fcntl, 我们实现一个SetNoBlock函数, 将文件描述符设置为非阻塞
void SetNonBlock(int fd)
{
     int flag = fcntl(fd,F_GETFL); //获取文件描述符标记
     if(flag < 0) //获取失败
     {
          cerr<<"code:"<<errno<<"string:"<<strerror(errno)<<endl;
          return;
     }
     fcntl(fd,F_SETFL,flag | O_NONBLOCK);
}

// 非阻塞式IO
int main()
{
    char buffer[64];
    SetNonBlock(0);
    LoadAllTask();
    while (true)
    {
        printf(">>>");
        PrintAllTask();
        fflush(stdout);
        int n = read(0, buffer, sizeof(buffer)); // read字节流读取--》等(检测就绪条件) + 拷贝
        //read读取数据的时候，最后的结果有三种：1.成功 2.结束 3.出错(一旦底层没有数据就绪，以出错的形式返回，但不算真正的出错)
        if(n > 0)
        {
            buffer[n - 1] = 0;                       // 干掉'\n'
            cout << "echo#" << buffer << endl;
        }else if(n == 0)
        {
          cerr<<"read end file >>> code:"<<errno<<"string:"<<strerror(errno)<<endl;
          break;
        }else
        {
            //所以对于非阻塞的出错的错误码，我们要进行细化
            if(errno == EAGAIN || errno == EWOULDBLOCK)
            {
                //底层没有数据就绪,需要read重新去检测
                sleep(1);
                cout<<"data not ready"<<endl;
                 continue;
            }else if(errno == EINTR)
            {
                //这次IO被信号中断了，需要重新检测
                continue;
            }else 
            {
              cerr<<"read error >>> code:"<<errno<<"string:"<<strerror(errno)<<endl;
              break;
            }
        }
    }
    return 0;
}